//
// Created by Gorun on 2022/5/3.
//

#include "LoxFunction.h"
#include "Environment.h"
#include "Interpreter.h"

LoxFunction::LoxFunction(std::shared_ptr<Function> declaration,
                         std::shared_ptr<Environment> closure,
                         bool isNative, bool isInitializer)
: declaration{move(declaration)}, closure{move(closure)},
isNative{isNative}, isInitializer{isInitializer}
{}

int LoxFunction::arity() {
    return static_cast<int>(declaration->params.size());
}

string LoxFunction::toString() {
    if (isNative)
        return "<native fn>";
    else
        return "<fn " + declaration->name.lexeme + " >";
}

any LoxFunction::call(Interpreter &interpreter, vector<any> arguments) {
    auto environment = make_shared<Environment>(closure);
    for (int i = 0; i < declaration->params.size(); i++) {
        environment->define(declaration->params[i].lexeme,
                            arguments[i]);
    }
    try {
        interpreter.executeBlock(declaration->body, environment);
    } catch (LoxReturn& returnValue) {
        if (isInitializer) return closure->getAt(0, "this");
        return returnValue.value;
    }

    if (isInitializer) return closure->getAt(0, "this");
    return {};
}

shared_ptr<LoxFunction> LoxFunction::bind(shared_ptr<LoxInstance> instance) {
    auto environment = make_shared<Environment>(closure);
    environment->define("this", instance);
    return make_shared<LoxFunction>(declaration, environment, false, isInitializer);
}
